package cn.sxw.android.base.kt

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Looper
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import cn.sxw.android.R
import cn.sxw.android.base.adapter.CustomDialogCallbackAdapter
import cn.sxw.android.base.app.ActivityStackManger
import cn.sxw.android.base.dialog.CustomDialogHelper
import cn.sxw.android.base.mvp.IViewAdvance
import cn.sxw.android.base.utils.JLogUtil
import cn.sxw.android.base.utils.KeyboardUtil
import cn.sxw.android.base.utils.NetworkUtil
import cn.sxw.android.base.utils.ToastUtils
import com.tbruyelle.rxpermissions2.RxPermissions
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

// 懒加载延时时长，单位：ms
const val LAZY_INIT_DELAY = 333L

/**
 * Created by ZengCS on 2021/6/25.
 * E-mail:zengcs@vip.qq.com
 * Add:中国成都
 * Desc:类说明
 */
abstract class BaseNormalKtActivity<T : ViewDataBinding, V : BaseViewModel> : BaseKtActivity(),
    IViewAdvance {
    companion object {
        const val KEY_ID = "KEY_ID"
        const val KEY_BOOLEAN = "KEY_BOOLEAN"
    }

    // 这里保证不会在多线程调用rxPermissions，所以取消同步锁，减少消耗
    val rxPermissions by lazy(LazyThreadSafetyMode.NONE) {
        RxPermissions(this)
    }

    protected var isLoading = false
    open fun isLazyInit(): Boolean = false
    private var isFullScreen = false
    private var progressDialog: AlertDialog? = null

    lateinit var binding: T
    lateinit var viewModel: V

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (ev.action == MotionEvent.ACTION_UP) {
            // ScreenSaverHelper.getInstance().updateLastUpTime()
        } else if (ev.action == MotionEvent.ACTION_DOWN) { //优化界面输入框 隐藏体验
            // get current focus,Generally it is EditText
            val view = currentFocus
            if (KeyboardUtil.isShouldHideSoftKeyBoard(view, ev)) {
                KeyboardUtil.hideSoft(this)
            }
        }
        return try {
            super.dispatchTouchEvent(ev)
        } catch (e: Exception) {
            false
        }
    }

    open fun needViewModel(): Boolean = true

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityStackManger.getInstance().addActivity(this)
        // 初始化ViewDataBinding
        initViewDataBinding()
        // 关联生命周期
        binding.lifecycleOwner = this
        // 设置布局文件
        setContentView(binding.root)
        // 初始化ViewModel
        if (needViewModel())
            initViewModel()
        // 程序初始化-入口
        onReady()
        // 判断懒加载流程
        if (isLazyInit()) {
            lifecycleScope.launch {
                delay(LAZY_INIT_DELAY)
                withContext(Dispatchers.Main) {
                    if (!isFinishing) {
                        onInit()
                        addOnClickListener()
                        hideLoading()
                    }
                }
            }
        } else {
            onInit()
            addOnClickListener()
        }
    }

    /**
     * 根据设置的类的泛型参数通过反射方式实例化ViewDataBinding对象
     */
    private fun initViewDataBinding() {
        val vbClass: Class<T> = getVMClass(this.javaClass, 0) as Class<T>
        try {
            val method: Method = vbClass.getMethod("inflate", LayoutInflater::class.java)
            binding = method.invoke(null, layoutInflater) as T
        } catch (e: Exception) {
            JLogUtil.e(Log.getStackTraceString(e))
        }
    }

    /**
     * 获取对应class类设置的第1个泛型参数对应的Class
     * @param clazz
     * @param actualTypeIndex 泛型參數索引位置
     * @return
     */
    private fun getVMClass(clazz: Class<*>, actualTypeIndex: Int): Type {
        val superClazz = clazz.genericSuperclass
        if (superClazz !is ParameterizedType) {
            throw RuntimeException("请设置类泛型")
        }
        return superClazz.actualTypeArguments[actualTypeIndex]
    }

    /**
     * 实例化ViewModel
     */
    private fun initViewModel() {
        val vmClass: Class<V> = getVMClass(this.javaClass, 1) as Class<V>
        // viewModel = ViewModelProvider(this).get(vmClass)
        viewModel = ViewModelProviders.of(this).get(vmClass)
        registerBaseObserver()
    }

    /**
     * 初始化ViewModel
     */
    private fun registerBaseObserver() {
        viewModel.showLoadingObserver.observe(this, Observer {
            if (it.isEmpty() || isFinishing) return@Observer
            if (it == BaseViewModel.TAG_HIDE_LOADING) {
                hideLoading()
            } else {
                showLoading(it)
            }
        })
        viewModel.showToastObserver.observe(this, Observer {
            if (it.isEmpty() || isFinishing) return@Observer
            showToast(it)
        })
        viewModel.showMessageObserver.observe(this, Observer {
            if (it.isEmpty() || isFinishing) return@Observer
            showMessage(it)
        })
    }

    override fun useEventBus(): Boolean {
        return false
    }

    override fun showLoading() {
        if (isFinishing) return
        showLoading(getString(R.string.txt_loading_common))
    }

    override fun hideLoading() {
        if (isFinishing) return
        isLoading = false
        progressDialog?.dismiss()
        if (isFullScreen) requestFullScreen(null)
    }

    override fun showMessage(message: String?) {
        if (isFinishing) return
        hideLoading()
        if (!isFinishing) CustomDialogHelper.showCustomMessageDialog(this, message)
    }

    open fun showExitMessageDialog(msg: String?) {
        if (isFinishing) return
        val dialogParam = CustomDialogHelper.DialogParam()
        dialogParam.message = msg
        dialogParam.positiveBtnText = "退出"
        CustomDialogHelper.showCustomMessageDialog(
            this,
            dialogParam,
            object : CustomDialogCallbackAdapter() {
                override fun onConfirm() {
                    killMyself()
                }
            })
    }

    override fun launchActivity(intent: Intent?, killIt: Boolean) {
        startActivity(intent)
        if (killIt)
            killMyself()
    }

    override fun launchActivity(clz: Class<*>?, killIt: Boolean) {
        launchActivity(Intent(this, clz))
        if (killIt)
            killMyself()
    }

    override fun isNetworkConnected(): Boolean {
        return NetworkUtil.isConnected()
    }

    override fun showLoading(msg: String?) {
        // 显示Loading框
        if (!isFinishing) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                runOnUiThread { forceShowLoading(msg) }
            } else {
                forceShowLoading(msg)
            }
        }
    }

    protected open fun getDataFromNet() {}

    override fun forceShowLoading(msg: String?) {
        if (isFinishing) return
        if (progressDialog == null) {
            val view: View = LayoutInflater.from(this).inflate(R.layout.dialog_custom_loading, null)
            val tips = view.findViewById<TextView>(R.id.tv_tip)
            tips.text = msg

            // progressDialog = new Dialog(this, R.style.CustomDialogWithDim);
            val builder = AlertDialog.Builder(this, R.style.CustomDialogFullScreen)
            builder.setView(view).setCancelable(false)
            try {
                progressDialog = builder.show()
                progressDialog?.setCanceledOnTouchOutside(false)
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        } else {
            val tips = progressDialog?.findViewById<TextView>(R.id.tv_tip)
            if (tips != null) tips.text = msg
        }
        if (!progressDialog?.isShowing!!) {
            if (!isFinishing) progressDialog?.show()
        }
    }

    override fun showToast(message: String?) {
        if (isFinishing) return
        if (TextUtils.isEmpty(message)) return
        ToastUtils.showLong(message)
    }

    override fun showShortcutMenu() {}

    override fun hideShortcutMenu() {}

    override fun hideSoftInput() {}

    override fun getAttachedContext(): Context? {
        return this
    }

    override fun getActivity(): Activity? {
        return this
    }

    override fun killMyself() {
        ActivityStackManger.getInstance().finishActivity(this)
        finish()
    }

    override fun onDestroy() {
        hideLoading()
        CustomDialogHelper.dismissDialog(progressDialog)
        progressDialog = null
        super.onDestroy()
        ActivityStackManger.getInstance().removeActivity(this)
    }

    /**
     * 移除全屏
     */
    protected open fun removeFullScreen() {
        isFullScreen = false
        val decorView = window.decorView
        decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
    }

    /**
     * 全屏
     */
    protected open fun requestFullScreen(keepScreenOn: Boolean?) {
        isFullScreen = true
        if (Build.VERSION.SDK_INT >= 19) {
            val decorView = window.decorView
            decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
        } else {
            val decorView = window.decorView
            val option = View.SYSTEM_UI_FLAG_FULLSCREEN
            decorView.systemUiVisibility = option
        }
        // 设置常亮
        if (keepScreenOn != null && keepScreenOn) setKeepScreenOn()
    }

    /**
     * 清除常亮
     */
    protected open fun clearKeepScreenOn() {
        try {
            window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 设置屏幕常亮
     */
    protected open fun setKeepScreenOn() {
        JLogUtil.d("setKeepScreenOn() called")
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    }

    protected val mAppName: String by lazy(LazyThreadSafetyMode.NONE) {
        getString(R.string.app_name)
    }

    // 从设置页面回来后，是否检测权限
    protected var autoCheckPermission = false

    /**
     * 默认是退出APP
     */
    @Deprecated("use onNeverAsk instead")
    fun onDenied(permissionName: String) {
        onDenied(permissionName, true)
    }

    @Deprecated("use onNeverAsk instead")
    fun onDenied(permissionName: String, withExit: Boolean) {
        val dialogParam = CustomDialogHelper.DialogParam()
        dialogParam.title = "授权被拒绝"
        dialogParam.message = "为保证${mAppName}的正常使用，请为${mAppName}授予[${permissionName}]权限。"
        dialogParam.positiveBtnText = "重新授权"
        dialogParam.negativeBtnText = if (withExit) "退出" else "取消"
        CustomDialogHelper.showCustomConfirmDialog(
            this,
            dialogParam,
            object : CustomDialogHelper.NativeDialogCallback {
                override fun onConfirm() {
                    onInit()
                }

                override fun onCancel() {
                    if (withExit)
                        onBackPressed()
                }
            })
    }

    /**
     * 1.默认是退出APP
     * 2.默认自动重新检测
     */
    fun onNeverAsk(permissionName: String) {
        onNeverAsk(permissionName, withExit = true, autoCheckOnResume = true)
    }

    /**
     * 拒绝授权并不再提示
     * @param permissionName    权限中文名称
     * @param withExit          如果拒绝，是否退出APP
     * @param autoCheckOnResume 用户进入应用设置返回后，是否自动检测授权状态
     */
    fun onNeverAsk(permissionName: String, withExit: Boolean, autoCheckOnResume: Boolean) {
        // 申请权限时被拒绝了，并且不再询问。
        val dialogParam = CustomDialogHelper.DialogParam()
        dialogParam.title = "授权被拒绝"
        dialogParam.message = "为保证${mAppName}的正常使用，请在应用设置中为${mAppName}授予[${permissionName}]权限。"
        dialogParam.positiveBtnText = "应用设置"
        dialogParam.negativeBtnText = if (withExit) "退出" else "取消"
        CustomDialogHelper.showCustomConfirmDialog(
            this,
            dialogParam,
            object : CustomDialogHelper.NativeDialogCallback {
                override fun onConfirm() {
                    openAppDetailSettings(autoCheckOnResume)
                }

                override fun onCancel() {
                    if (withExit)
                        onBackPressed()
                }
            })
    }

    fun showPermissionTips(permissionName: String) {
        showToast("为保证${mAppName}的正常使用，请在应用设置中为${mAppName}授予[${permissionName}]权限。")
    }


    var goAdd = false

    override fun onResume() {
        super.onResume()
        if (autoCheckPermission) {
            lifecycleScope.launch {
                delay(1000)
                withContext(Dispatchers.Main) {
                    if (!isFinishing) {
                        onInit()
                    }
                }
                autoCheckPermission = false
            }
        }
        if (goAdd) {
            initData()
        }
    }

    /**
     * 打开应用程序设置界面
     */
    protected open fun openAppDetailSettings() {
        openAppDetailSettings(true)
    }

    /**
     * @param checkPermissionOnResume 授权回来后是否自动检测授权状态
     */
    protected open fun openAppDetailSettings(checkPermissionOnResume: Boolean) {
        autoCheckPermission = checkPermissionOnResume
        try {
            val intent = Intent()
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
            intent.data = Uri.fromParts("package", packageName, null)
            startActivity(intent)
        } catch (e: Exception) {
            showMessage(e.message)
        }
    }
}